package ui;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.font.*;
import java.math.*;
import java.io.*;
/*
import java.lang.*;
import java.util.Timer;
import java.util.TimerTask;
*/

public class Screen extends JFrame implements WindowListener {

  /* fonts and colors */
  private Font textFont, glyphFont;
  private int [] frameHighColor = { 50, 250, 50};
  private int [] frameLowColor = {0, 200, 0};
  private int [] textColor = {150, 150, 250};

  /* font dimensions and padding */
  private int textCharWidth = 12;
  private int textCharHeight = 18;
  private int textPadWidth = 8;
  private int textPadHeight = 5;
  private int mapCharWidth = 18;
  private int mapCharHeight = 18;
  private int mapPadWidth = 12;
  private int mapPadHeight = 4;

  /* dimensions (in number of characters) of the frame + 3 regions */
  public int mapWidth = 42; /* not including frame + must be divisible */
  public int mapHeight = 32; /* not including frame + must be divisible */
  private int statusWidth = 16;
  private int statusHeight = 0; /* calculated */
  private int messageWidth = 0; /* calculated */
  private int messageHeight = 6;
  private int frameWidth; /* calculated */
  private int frameHeight; /* calculated */

  /* location (in pixel offset from upper left) of the frame + 3 regions */
  private int mapX, mapY;
  private int frameX, frameY;
  private int messageX, messageY;
  private int statusX, statusY;

  /* screen character arrays for the 3 regions */
  public ScreenChar [][] mapChar;
  private ScreenChar [][] statusChar;
  private ScreenChar [][] messageChar;

  /* total screen size and padding (in pixels) */
  private int regionPadding = 14;
  private int topPadding = 22 + regionPadding;
  private int screenWidth, screenHeight;

  /* animation variables */
  public Timer animation;
  public int animArrayI = 0;
  public int animArrayN = 30;
  public double [] animArray;

  /* message buffer variables */
  private int oldMessage = 0;
  private int endMessage = 0;

  public Screen(Input input) {

    /* argument to new Frame() */
    super("-{--- Iron Age ---}-");

    /* load and configure the bundled fonts */
    try {
      InputStream ins = this.getClass().getResourceAsStream("/roguelike.ttf");
      Font tmptext = Font.createFont(Font.TRUETYPE_FONT, ins);
      textFont = tmptext.deriveFont(20f);
    } catch (IOException e) {
      System.out.println(e.getMessage());
      System.exit(1);
    } catch (FontFormatException e) {
      System.out.println(e.getMessage());
      System.exit(1);
    }

    /* calculate the total width of the window */
    screenWidth = statusWidth * textCharWidth; /* status window */
    screenWidth += mapWidth * mapCharWidth; /* map window */
    screenWidth += 2 * textCharWidth; /* map frame */
    screenWidth += 3 * regionPadding; /* padding */

    /* calculate the total height of the window */
    screenHeight = mapHeight * mapCharHeight; /* map window */
    screenHeight += messageHeight * textCharHeight; /* message window */
    screenHeight += 2 * textCharHeight; /* map frame */
    screenHeight += topPadding + (2 * regionPadding); /* padding */

    /* status area */
    statusX = regionPadding; /* padding */
    statusY = topPadding; /* padding */
    statusHeight = 2; /* map frame */
    statusHeight += (mapHeight * mapCharHeight) / textCharHeight; /* map */
    statusHeight += regionPadding / textCharHeight; /* padding */
    statusHeight += messageHeight; /* message */

    statusChar = new ScreenChar[statusWidth][statusHeight];
    for(int i = 0; i < statusWidth; i++) {
      for(int j = 0; j < statusHeight; j++) {
        statusChar[i][j] = new ScreenChar(textCharWidth, textCharHeight, textFont, glyphFont);
        statusChar[i][j].setChar(' ', textColor);
      }
    }

    /* map frame */
    frameX = 2 * regionPadding; /* padding */
    frameX += (statusWidth * textCharWidth); /* status */
    frameY = topPadding; /* padding */
    frameWidth = ((mapWidth * mapCharWidth) / textCharWidth) + 2;
    frameHeight = ((mapHeight * mapCharHeight) / textCharHeight) + 2;

    /* map area */
    mapX = 2 * regionPadding; /* padding */
    mapX += (statusWidth * textCharWidth); /* status */
    mapX += textCharWidth; /* map frame */
    mapY = topPadding; /* padding */
    mapY += textCharHeight; /* map frame */
    mapY += 4; /* some other stuff */

    mapChar = new ScreenChar[mapWidth][mapHeight];
    for(int i = 0; i < mapWidth; i++) {
      for(int j = 0; j < mapHeight; j++) {
        mapChar[i][j] = new ScreenChar(mapCharWidth, mapCharHeight, textFont, glyphFont);
        mapChar[i][j].setCenter();
      }
    }

    /* message area */
    messageX = 2 * regionPadding; /* padding */
    messageX += (statusWidth * textCharWidth); /* status */
    messageY = topPadding + regionPadding; /* padding */
    messageY += (mapHeight * mapCharHeight); /* map */
    messageY += 2 * textCharHeight; /* map frame */
    messageWidth = 2; /* map frame */
    messageWidth += (mapWidth * mapCharWidth) / textCharWidth;

    messageChar = new ScreenChar[messageWidth][messageHeight];
    for(int i = 0; i < messageWidth; i++) {
      for(int j = 0; j < messageHeight; j++) {
        messageChar[i][j] = new ScreenChar(textCharWidth, textCharHeight, textFont, glyphFont);
        messageChar[i][j].setChar(' ', textColor);
      }
    }

    /* initialize the window */
    setBackground(Color.black);
    setSize(screenWidth, screenHeight);
    setResizable(false);
    setVisible(true);

    addWindowListener(this);
    addKeyListener(input);

    /* initialize the animation timer */
    /*
    animation = new Timer();
    TimerTask animationTask = new TimerTask() {
      public void run() {
        animationUpdate();
      }
    };
    animation.schedule(animationTask, 50, 50);
    animArray = new double[animArrayN];
    setAnimArray();
    */

  }

  public void paint(Graphics g) {

    Image buffer = createImage(screenWidth, screenHeight);
    Graphics b = buffer.getGraphics();

    /* ugly shit for anti-aliasing */
    Graphics2D b2d = (Graphics2D) b;
    b2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

    animArrayI = 0;

    paintMapFrame(b, "Untamed Wilds");
    paintMap(b);
    paintMessage(b);
    paintStatus(b);

    g.drawImage(buffer, 0, 0, this);

  }

  private void paintMap(Graphics g) {
    g.setFont(textFont);
    for(int i = 0; i < mapWidth; i++) {
      for(int j = 0; j < mapHeight; j++) {
        int x = mapX + (i * mapCharWidth);
        int y = mapY + (j * mapCharHeight);
        mapChar[i][j].display(g, x, y);
      }
    }
  }

  private void paintMessage(Graphics g) {
    g.setFont(textFont);
    for(int i = 0; i < messageWidth; i++) {
      for(int j = 0; j < messageHeight; j++) {
        int x = messageX + (i * textCharWidth);
        int y = messageY + (j * textCharHeight);
        messageChar[i][j].display(g, x, y);
      }
    }
  }

  private void shiftMessage() {
    for(int i = 1; i < endMessage; i++) {
      for(int j = 0; j < messageWidth; j++) {
        char ch = messageChar[j][i].getChar();
        int [] cl = messageChar[j][i].getColor();
        messageChar[j][i-1].setChar(ch, cl);
      }
    }
    if(oldMessage > 0) oldMessage--;
    if(endMessage > 0) endMessage--;
  }

  public void addMessage(String s) {
    if(endMessage == messageHeight) shiftMessage();
    for(int i = 0; i < messageWidth; i++) {
      char ch;
      if(i < s.length()) ch = s.charAt(i);
      else ch = ' ';
      messageChar[i][endMessage].setChar(ch, textColor);
    }
    endMessage++;
  }

  public void ageMessage(String s) {
  }

  private void paintStatus(Graphics g) {

    g.setFont(textFont);
    for(int i = 0; i < statusWidth; i++) {
      for(int j = 0; j < statusHeight; j++) {
        int x = statusX + (i * textCharWidth);
        int y = statusY + (j * textCharHeight);
        statusChar[i][j].display(g, x, y);
      }
    }

  }

  private void paintMapFrame(Graphics g, String t) {

    int x, y;
    int sb, se;
    int i;
    char c;
    ScreenChar sc = new ScreenChar(textCharWidth, textCharHeight, textFont, glyphFont);
    
    g.setFont(textFont);

    /* draw the top */
    for(i = 0; i < frameWidth; i++) {
      if(i == 0 || i == frameWidth - 1) c = '+';
      else if(i == (frameWidth / 2)) c = 'O';
      else if(i == (frameWidth / 2) - 1) c = '(';
      else if(i == (frameWidth / 2) + 1) c = ')';
      else if(i == (frameWidth / 2) - 2) c = '<';
      else if(i == (frameWidth / 2) + 2) c = '>';
      else if(i == (frameWidth / 2) - 3) c = '=';
      else if(i == (frameWidth / 2) + 3) c = '=';
      else if(i == (frameWidth / 2) - 4) c = '=';
      else if(i == (frameWidth / 2) + 4) c = '=';
      else if(i == (frameWidth / 2) - 5) c = '=';
      else if(i == (frameWidth / 2) + 5) c = '=';
      else c = '-';
      x = frameX + (i * textCharWidth);
      y = frameY;
      if(i >= (frameWidth / 2) - 1 && i <= (frameWidth / 2) + 1)
        sc.setChar(c, frameHighColor);
      else
        sc.setChar(c, frameLowColor);
      sc.display(g, x, y);
    }

    /* draw the sides */
    for(i = 1; i < frameHeight - 1; i++) {
      c = '|';
      sc.setChar(c, frameLowColor);
      x = frameX;
      y = frameY + (i * textCharHeight);
      sc.display(g, x, y);
      x = frameX + ((frameWidth - 1) * textCharWidth);
      y = frameY + (i * textCharHeight);
      sc.display(g, x, y);
    }

    /* draw the bottom */
    sb = (frameWidth / 2) - (t.length() / 2);
    se = sb + t.length();
    for(i = 0; i < frameWidth; i++) {
      if(i == 0 || i == frameWidth - 1) c = '+';
      else if(i >= sb && i < se) c = t.charAt(i - sb);
      else if(i == sb - 1) c = ' ';
      else if(i == se) c = ' ';
      else if(i == sb - 2) c = '<';
      else if(i == se + 1) c = '>';
      else c = '-';
      x = frameX + (i * textCharWidth);
      y = frameY + ((frameHeight - 1) * textCharHeight);
      if(i >= sb - 2 && i <= se + 1)
        sc.setChar(c, frameHighColor);
      else
        sc.setChar(c, frameLowColor);
      sc.display(g, x, y);
    }
  }

  private void animationUpdate() {
    setAnimArray();
    repaint();
  }

  private Color toColor(int [] i) {
    return(new Color(i[0], i[1], i[2]));
  }

  private Color animColor(int [] low, int [] hi) {
    double v = animArray[animArrayI];
    int [] c = new int[3];
    animArrayI = (animArrayI + 1) % animArrayN;
    for(int i = 0; i < 3; i++)
      c[i] = low[i] + (int) (((double) hi[i] - (double) low[i]) * v);
    return(toColor(c));
  }

  public void setAnimArray() {
    for(int i = 0; i < animArrayN; i++) {
      animArray[i] = Math.random();
    }
  }

  public void windowClosing(WindowEvent event) {
    System.exit(0);
  }
  public void windowClosed(WindowEvent event) { }
  public void windowDeiconified(WindowEvent event) { }
  public void windowIconified(WindowEvent event) { }
  public void windowActivated(WindowEvent event) { }
  public void windowDeactivated(WindowEvent event) { }
  public void windowOpened(WindowEvent event) { }

}
